package charts ;
import charts.series.pies.PieLabel;
import flash.external.ExternalInterface;
import string.Utils;
import charts.series.Element;
import charts.series.pies.PieSliceContainer;
import charts.series.pies.DefaultPieProperties;
import global.Global;
import ColorConverter.Color;
import charts.Base.DISTANCESTRUCT;

import flash.display.Sprite;

typedef PIESTRUCT = {
	var labels		: Array<String>;
	var links		: Array<String>;
	var colors		: Array<Float>;
	var gradientFill	: Bool;
	var border_width	: Float;
	var label_line		: Float;
	var total_value		: Int;
}

class Pie extends Base
{
	var labels:Array<String>;
	var links:Array<String>;
	var colors:Array<Float>;
	//var gradientFill:String = 'true'; //toggle gradients
	var gradientFill:Bool;
	//var border_width: Float = 1;
	var border_width: Float;
	var label_line: Float;
	//var easing : Dynamic;
	public var style: Dynamic;
	//public var total_value: Float = 0;
	public var total_value: Float;
	
	// new:
	var props:Properties;
	//
	
	public function new ( json: Dynamic )
	{
		super();

		gradientFill = true;
		border_width = 1;
		total_value = 0;

		this.labels = new Array<String>();
		this.links = new Array<String>();
		this.colors = new Array<Float>();
		
		this.style = {
			colors:	[Hex("#900000"), Hex("#009000")]	// slices colors
		}
		
		ObjectHelper.merge_2( json, this.style );			
		
		//var _colors : Array<Dynamic> = cast(this.style.colors,Array<Dynamic>);
		//for ( color in _colors )
		//	this.colors.push( string.Utils.get_color( color ) );
		style.colors = cast(style.colors, Array<Color>);
		for ( c in style.colors )
		{
			colors.push(ColorConverter.toInt(c));
		}

		this.props = new DefaultPieProperties(json);

		this.label_line = 10;

		this.values = json.values;
		this.add_values();
	}
	
	
	//
	// Pie chart make is quite different to a normal make
	//
	public override function add_values(): Void {
		//
		// Warning: this is our global singleton
		//
		var g:Global = Global.getInstance();
		
		var total: Float = 0;
		var slice_start: Float = this.props.get('start-angle');
		var i: Int;
		var val: Dynamic;
		
		for ( val in this.values ) {
			if(Std.is(val,Float ))
				total += val;
			else
				total += val.value;
		}
		this.total_value = total;
		
		i = 0;
		for ( val in this.values ) {
			
			//var value: Float = val is Number ? cast(val,Number): val.value;
			var value : Float = if (Std.is(val,Float)) val else val.value;
			var slice_angle: Float = value*360/total;
			
			if( slice_angle >= 0 )
			{
				
				var t:String = cast(this.props.get('tip'), String);
				t = StringTools.replace(t, '#total#', NumberUtils.formatNumber( Std.int(this.total_value)));
				t = StringTools.replace(t, '#percent#', NumberUtils.formatNumber( Std.int(value / Std.float(this.total_value) * 100 )) + '%');
			
				this.addChild(
					this.add_slice(
						i,
						slice_start,
						slice_angle,
						val,		// <-- NOTE: val (object) NOT value (a number)
						t,
						this.colors[(i % this.colors.length)]
						)
					);

				// TODO: fix this and remove
				// tmp.make_tooltip( this.key );
			}
			i++;
			slice_start += slice_angle;
		}
	}
	
	function add_slice( index: Int, start: Float, angle: Float, value: Dynamic, tip:String, color:String ): PieSliceContainer {
		
			
		// Properties chain:
		//   pie-slice -> calculated-stuff -> pie
		//
		// calculated-stuff:
		var calculated_stuff:Properties = new Properties(
			{
				color:				color,		// <-- from the color cycle array
				tip:				tip,		// <-- replaced the #total# & #percent# for this slice
				start:				start,		// <-- calculated
				angle:				angle		// <-- calculated
			},
			this.props );
		
		var tmp: Dynamic = {};			
		if (Std.is(value,Float))
			tmp.value = value;
		else
			tmp = value;
			
		var p:Properties = new Properties( tmp, calculated_stuff );
		
		// no user defined label?
		if ( !p.has('label') )
			p.set('label', p.get('value').toString());
		
		// tr.aces( 'value', p.get('value'), p.get('label'), p.get('color') );
		return new PieSliceContainer( index, p );
	}
	
	
	public override function closest ( x: Float, y: Float ): DISTANCESTRUCT {
		// PIE charts don't do closest to mouse tooltips
		return { Element:null, distance_x:0, distance_y:0 };
	}


	public override function resize ( sc:ScreenCoordsBase ): Void {
		var radius: Float = this.style.radius;
		var sliceContainer:PieSliceContainer;
		var ticAngle: Float;

		if (Math.isNaN(radius)){
			radius = ( Math.min( sc.width, sc.height ) / 2.0 );
			var offsets: Dynamic = {top:0, right:0, bottom:0, left:0};
			trace("sc.width, sc.height, radius", sc.width, sc.height, radius);

			//var i: Float;

			// loop to gather and merge offsets
			for ( i in 0...this.numChildren ) {
				sliceContainer = cast(this.getChildAt(i),PieSliceContainer);
				var pie_offsets : OFFSETSTRUCT = sliceContainer.get_radius_offsets();
				var offset_fields : Array<String> = Reflect.fields(pie_offsets);
				for ( key in offset_fields ) {
					if ( Reflect.field(pie_offsets, key) > Reflect.field(offsets,key) ) {
						Reflect.setField(offsets, key, Reflect.field(pie_offsets, key));
					}
				}
			}
			var vRadius: Float = radius;
			// Calculate minimum radius assuming the contraInt is vertical
			// Shrink radius by the largest top/bottom offset
			vRadius -= Math.max(offsets.top, offsets.bottom);
			// check to see if the left/right labels will fit
			if ((vRadius + offsets.left) > (sc.width / 2))
			{
				//radius -= radius + offsets.left - (sc.width / 2);
				vRadius = (sc.width / 2) - offsets.left;
			}
			if ((vRadius + offsets.right) > (sc.width / 2))
			{
				//radius -= radius + offsets.right - (sc.width / 2);
				vRadius = (sc.width / 2) - offsets.right;
			}

			// Make sure the radius is at least 10
			radius = Math.max(vRadius, 10);
		}

		var rightTopTicAngle: Float		= 720;
		var rightTopTicIdx: Float		= -1;
		var rightBottomTicAngle: Float	= -720;
		var rightBottomTicIdx: Float	= -1;

		var leftTopTicAngle: Float		= 720;
		var leftTopTicIdx: Float		= -1;
		var leftBottomTicAngle: Float	= -720;
		var leftBottomTicIdx: Float		= -1;

		// loop and resize
		for ( i in 0...this.numChildren )
		{
			sliceContainer = cast(this.getChildAt(i),PieSliceContainer);
			sliceContainer.pie_resize(sc, radius);

			// While we are looping through the children, we determine which
			// labels are the starting points in each quadrant so that we
			// move the labels around to prevent overlaps
			ticAngle = sliceContainer.getTicAngle();
			if (ticAngle >= 270)
			{
				// Right side - Top
				if ((ticAngle < rightTopTicAngle) || (rightTopTicAngle <= 90))
				{
					rightTopTicAngle = ticAngle;
					rightTopTicIdx = i;
				}
				// Just in case no tics in Right-Bottom
				if ((rightBottomTicAngle < 0) ||
					((rightBottomTicAngle > 90) && (rightBottomTicAngle < ticAngle)))
				{
					rightBottomTicAngle = ticAngle;
					rightBottomTicIdx = i;
				}
			}
			else if (ticAngle <= 90)
			{
				// Right side - Bottom
				if ((ticAngle > rightBottomTicAngle) || (rightBottomTicAngle > 90))
				{
					rightBottomTicAngle = ticAngle;
					rightBottomTicIdx = i;
				}
				// Just in case no tics in Right-Top
				if ((rightTopTicAngle > 360) ||
					((rightTopTicAngle <= 90) && (ticAngle < rightBottomTicAngle)))
				{
					rightTopTicAngle = ticAngle;
					rightTopTicIdx = i;
				}
			}
			else if (ticAngle <= 180)
			{
			// Left side - Bottom
			if ((leftBottomTicAngle < 0) || (ticAngle < leftBottomTicAngle))
			{
				leftBottomTicAngle = ticAngle;
				leftBottomTicIdx = i;
			}
			// Just in case no tics in Left-Top
			if ((leftTopTicAngle > 360) || (leftTopTicAngle < ticAngle))
			{
				leftTopTicAngle = ticAngle;
				leftTopTicIdx = i;
			}
			}
			else
			{
				// Left side - Top
				if ((leftTopTicAngle > 360) || (ticAngle > leftTopTicAngle))
				{
					leftTopTicAngle = ticAngle;
					leftTopTicIdx = i;
				}
				// Just in case no tics in Left-Bottom
				if ((leftBottomTicAngle < 0) || (leftBottomTicAngle > ticAngle))
				{
					leftBottomTicAngle = ticAngle;
					leftBottomTicIdx = i;
				}
			}
		}

		// Make a clockwise pass on right side of pie trying to move
		// the labels so that they do not overlap
		var childIdx: Float = rightTopTicIdx;
		var yVal: Float = sc.top;
		var bDone:Bool = false;
		while ((childIdx >= 0) && (!bDone))
		{
			sliceContainer = cast(this.getChildAt(childIdx),PieSliceContainer);
			ticAngle = sliceContainer.getTicAngle();
			if ((ticAngle >= 270) || (ticAngle <= 90))
			{
				yVal = sliceContainer.moveLabelDown(sc, yVal);

				childIdx++;
				if (childIdx >= this.numChildren) childIdx = 0;

				bDone = (childIdx == rightTopTicIdx);
			}
			else
			{
				bDone = true;
			}
		}

		// Make a counter-clockwise pass on right side of pie trying to move
		// the labels so that they do not overlap
		childIdx = rightBottomTicIdx;
		yVal = sc.bottom;
		bDone = false;
		while ((childIdx >= 0) && (!bDone))
		{
			sliceContainer = cast(this.getChildAt(childIdx),PieSliceContainer);
			ticAngle = sliceContainer.getTicAngle();
			if ((ticAngle >= 270) || (ticAngle <= 90))
			{
				yVal = sliceContainer.moveLabelUp(sc, yVal);

				childIdx--;
				if (childIdx < 0) childIdx = this.numChildren - 1;

				bDone = (childIdx == rightBottomTicIdx);
			}
			else
			{
				bDone = true;
			}
		}

		// Make a clockwise pass on left side of pie trying to move
		// the labels so that they do not overlap
		childIdx = leftBottomTicIdx;
		yVal = sc.bottom;
		bDone = false;
		while ((childIdx >= 0) && (!bDone))
		{
			sliceContainer = cast(this.getChildAt(childIdx),PieSliceContainer);
			ticAngle = sliceContainer.getTicAngle();
			if ((ticAngle > 90) && (ticAngle < 270))
			{
				yVal = sliceContainer.moveLabelUp(sc, yVal);

				childIdx++;
				if (childIdx >= this.numChildren) childIdx = 0;

				bDone = (childIdx == leftBottomTicIdx);
			}
			else
			{
				bDone = true;
			}
		}

		// Make a counter-clockwise pass on left side of pie trying to move
		// the labels so that they do not overlap
		childIdx = leftTopTicIdx;
		yVal = sc.top;
		bDone = false;
		while ((childIdx >= 0) && (!bDone))
		{
			sliceContainer = cast(this.getChildAt(childIdx),PieSliceContainer);
			ticAngle = sliceContainer.getTicAngle();
			if ((ticAngle > 90) && (ticAngle < 270))
			{
				yVal = sliceContainer.moveLabelDown(sc, yVal);

				childIdx--;
				if (childIdx < 0) childIdx = this.numChildren - 1;

				bDone = (childIdx == leftTopTicIdx);
			}
			else
			{
				bDone = true;
			}
		}
	}

	
	public override function toString ():String {
		return "Pie with "+ this.numChildren +" children";
	}
}
